from django.shortcuts import render
from django.views import View
from QQLoginTool.QQtool import OAuthQQ
from django.conf import settings
from django.http import JsonResponse
from apps.oauth.models import OAuthQQUser
from django.contrib.auth import login
from apps.oauth.utils import generate_access_token_openid, check_access_token_openid
import json
import re
from django_redis import get_redis_connection
from apps.users.models import User
from django.db import DatabaseError


# Create your views here.


class QQURLView(View):
    """
    QQ扫码登录链接
    GET /qq/authorization
    """

    def get(self, request):
        """
        提供QQ登录页面网址
        :return: login_url QQ 登录扫码页面链接
        """

        # 接收 next 参数
        # next 用于记录 QQ 登录成功后进入的网址
        next = request.GET.get('next', '/')

        # 获取 QQ 登录页面网址
        # 创建OAuthQQ对象
        # oauth = OAuthQQ(client_id='101474184',
        #                 client_secret='c6ce949e04e12ecc909ae6a8b09b637c',
        #                 redirect_uri='http://www.meiduo.site:8080/oauth_callback.html',
        #                 state=next)
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI,
                        state=next)

        # 调用提供QQ登录扫码链接的接口函数
        # 获取qq地址方法
        login_url = oauth.get_qq_url()

        # 响应登录地址
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'login_url': login_url
        })


class QQUserView(View):
    """用户扫码登录的回调处理"""

    def get(self, request):
        """处理授权后的回调逻辑
        code    QQ 发送过来用于验证的字段
        """
        # 获取前端发送过来的 code 参数
        code = request.GET.get('code')
        # 判断 code 参数是否存在
        if not code:
            return JsonResponse({
                'code': 400,
                'errmsg': '缺少code参数'
            })

        # 安装 QQLoginTool 工具类
        # pip install QQLoginTool
        # 调用安装的 QQLoginTool 工具类
        # 创建SDK的对象
        oauth = OAuthQQ(client_id=settings.QQ_CLIENT_ID,
                        client_secret=settings.QQ_CLIENT_SECRET,
                        redirect_uri=settings.QQ_REDIRECT_URI, )

        try:
            # 使用code获取access_token
            access_token = oauth.get_access_token(code)
            # 使用access_token向qq服务器请求获取 openid
            openid = oauth.get_open_id(access_token)

        except Exception as e:
            return JsonResponse({
                'code': 400,
                'errmsg': 'OAuth2.0认证失败,即获取qq信息失败'
            })

        # 使用openid 去判断当前的QQ用户是否已经绑定过美多商城(纯属美多商城自己的需求,跟oauth2.0无关)
        try:
            # 使用openid作为查询条件
            # QQ登录模型类.objects.get(openid=oauth认证的openid)
            oauth_model = OAuthQQUser.objects.get(openid=openid)

        except OAuthQQUser.DoesNotExist:
            # 进入这里说明 openid 未绑定美多商城用户:将用户引导到绑定页面
            # 对 openid 加密,成为access_token
            access_token = generate_access_token_openid(openid)
            # 把 access_token 返回给前端
            # 注意: 这里一定不能返回 0 的状态码. 否则不能进行绑定页面
            return JsonResponse({
                'code': 300,
                'errmsg': 'QQ登录未绑定美多用户',
                'access_token': access_token
            })

        else:
            # openid 已经绑定美多商城用户:直接实现状态保持即可
            # 在实现qq登录时,真正登录的是qq用户绑定的美多商城用户
            # user = '跟openid绑定的美多商城的用户对象'
            # oauth_model对应的是openid查询出来的一条记录
            # oauth_model.user对应的是跟openid关联的用户对象
            user = oauth_model.user

            # 实现状态保持
            login(request, user)

            # 创建重定向到主页的对象
            response = JsonResponse({
                'code': 0,
                'errmsg': 'ok'
            })

            # 将用户信息写入到 cookie 中,有效期14天
            response.set_cookie(
                'username',
                oauth_model.user.username,
                max_age=3600 * 24 * 14)

            # 合并购物车
            from apps.carts.utils import merge_cart_cookie_to_redis
            response = merge_cart_cookie_to_redis(request, user, response)

            # 返回响应
            return response

    def post(self, request):
        """实现openid绑定美多用户后端逻辑"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        mobile = json_dict.get('mobile')
        password = json_dict.get('password')
        sms_code_client = json_dict.get('sms_code')
        access_token = json_dict.get('access_token')

        # 校验参数
        # 判断参数是否齐全
        if not all([mobile, password, sms_code_client, access_token]):
            return JsonResponse({
                'code': 400,
                'errmsg': '缺少必传参数'
            })
        if not re.match(r'^1[3-9]\d{9}', mobile):
            return JsonResponse({
                'code': 400,
                'errmsg': '请输入正确手机号'
            })
        # 判断密码是否合格
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return JsonResponse({'code': 400,
                                'errmsg': '请输入8-20位的密码'})

        # 创建redis链接对象
        redis_conn = get_redis_connection('verify_code')
        # 从 redis 中获取 sms_code 值
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        # 判断获取出来的有没有:
        if sms_code_server is None:
            # 如果没有, 直接返回:
            return JsonResponse({'code': 400,
                                'errmsg': '验证码失效'})
        # 如果有, 则进行判断:
        if sms_code_client != sms_code_server.decode():
            # 如果不匹配, 则直接返回:
            return JsonResponse({'code': 400,
                                'errmsg': '输入的验证码有误'})

        # 校验openid
        openid = check_access_token_openid(access_token)
        if not openid:
            return JsonResponse({
                'code': 400,
                'errmsg': '缺少openid'
            })

        # 保存注册数据
        # 判断手机号对应的用户是否存在
        try:
            user = User.objects.get(mobile=mobile)
        except User.DoesNotExist:
            # 如果手机号对应的用户不存在,新建用户
            user = User.objects.create_user(
                username=mobile,
                password=password,
                mobile=mobile
            )
        else:
            # 如果手机号对应的用户存在,校验密码
            if not user.check_password(password):
                return JsonResponse({
                    'code': 400,
                    'errmsg': '输入的密码错误'
                })

        try:
            # 将上面得到的用户跟openid进行绑定
            # create_user(): 只有继承自AbstractUser的用户模型类才能调用,用来创建用户记录
            # create(): 凡是继承自Model的模型类都可以调用,用来创建记录
            OAuthQQUser.objects.create(openid=openid,
                                       user=user)
        except DatabaseError:
            return JsonResponse({
                'code': 400,
                'errmsg': '给数据库添加数据失败'
            })

        # 实现状态保持
        login(request, user)

        # 创建响应对象
        response = JsonResponse({
            'code': 0,
            'errmsg': 'ok'
        })
        # 登录时用户名写入到cookie,有效期14 天
        response.set_cookie('username',
                            user.username,
                            max_age=3600 * 24 * 14)

        # 合并购物车
        from apps.carts.utils import merge_cart_cookie_to_redis
        response = merge_cart_cookie_to_redis(request, user, response)

        # 响应结果
        return response
